package com.basswold.nasaesa.client;

import com.google.gwt.core.client.EntryPoint;
import com.google.gwt.core.client.JavaScriptObject;
import com.google.gwt.dom.client.Style.Unit;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.http.client.RequestBuilder;
import com.google.gwt.http.client.RequestCallback;
import com.google.gwt.http.client.Request;
import com.google.gwt.http.client.RequestException;
import com.google.gwt.http.client.Response;
import com.google.gwt.http.client.URL;
import com.google.gwt.i18n.client.Dictionary;
import com.google.gwt.json.client.JSONArray;
import com.google.gwt.json.client.JSONNumber;
import com.google.gwt.json.client.JSONObject;
import com.google.gwt.json.client.JSONParser;
import com.google.gwt.json.client.JSONString;
import com.google.gwt.json.client.JSONValue;
import com.google.gwt.jsonp.client.JsonpRequestBuilder;
import com.google.gwt.storage.client.Storage;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.FlexTable;
import com.google.gwt.user.client.ui.Grid;
import com.google.gwt.user.client.ui.Image;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.ListBox;
import com.google.gwt.user.client.ui.PushButton;
import com.google.gwt.user.client.ui.RootLayoutPanel;
import com.google.gwt.user.client.ui.ScrollPanel;
import com.google.gwt.user.client.ui.SplitLayoutPanel;
import com.google.gwt.user.client.ui.StackLayoutPanel;
import com.google.gwt.user.client.ui.TextBox;

/**
 * Entry point classes define <code>onModuleLoad()</code>.
 */
public class CS4531 implements EntryPoint {

	/**
	 * This is the entry point method.
	 */
	Button minConfigBtn1;
	Button minConfigBtn2;
	Button minConfigBtn3;
	PushButton crossBaseBtn;
	PushButton HBaseBtn;
	PushButton sixWingBaseBtn;

	final String groundLocation = "images/ground.png";
	final int sandyMinX = 40;
	final int sandyMaxX = 50;
	final int sandyMinY = 40;
	final int sandyMaxY = 50;

	Storage moduleStore = null;

	//Button alertButton = new Button("Minimum Configurations Available!");
	Button saveConfig = new Button("Save Configuration");
	Button addMod = new Button("+");

	private TextBox idBox = new TextBox();
	private TextBox xBox = new TextBox();
	private TextBox yBox = new TextBox();

	ScrollPanel scrollAddForm = new ScrollPanel();
	ScrollPanel scrollBottomPanel = new ScrollPanel();
	FlexTable addform = new FlexTable();
	private ScrollPanel ModContainer[] = new ScrollPanel[10];
	private FlexTable Mods[] = new FlexTable[10];
	private FlexTable bottomPanel = new FlexTable();
	//final Grid g = new Grid(50,100); // Grid(ySize,xSize)
	final Grid g = new Grid(50,100);
	final StackLayoutPanel panel = new StackLayoutPanel(Unit.EM);

	private boolean minreached = false;
	private String modListKey = "modList";
	private String configKey = "config";
	int configNum = 0;
	private String configWatch = "maxConfig"; // keeps track of the biggest configNum in local storage
	private ModuleList modList = new ModuleList();
	private ModuleList damagedModList = new ModuleList();
	final static String modTypes[] = {
		"Plain",
		"Dormitory",
		"Sanitation",
		"Food",
		"Gym",
		"Canteen",
		"Power",
		"Control",
		"Airlock",
	"Medical"};

	public void onModuleLoad() {

		g.setCellPadding(0);
		g.setCellSpacing(0);
		final ListBox satNum = new ListBox();
		final ListBox orientList = new ListBox();
		final ListBox condList = new ListBox();

		for( int i = 1; i <= 8; i++){
			satNum.addItem(String.valueOf(i));
		}
		//Create stack panel for module list  
		for( int i = 0; i < Module.orientavail.length ; i++){
			orientList.addItem(Module.orientavail[i].toString());
		}

		for( int i = 0; i < Module.condavail.length ; i++){
			condList.addItem(Module.condavail[i].toString());
		}

		Button loadMod = new Button("Load Modules");
		loadMod.addClickHandler(new ClickHandler() {
			public void onClick(ClickEvent event) {
				restoreList();
				checkStatus(0);
				updateGrid();
			}
		});

		Button saveMod = new Button("Save Modules");
		saveMod.addClickHandler(new ClickHandler() {
			public void onClick(ClickEvent event) {
				storeList();
			}
		});

		Button loadStore = new Button("Load Storage");
		loadStore.addClickHandler(new ClickHandler() {
			public void onClick(ClickEvent event) {
				restoreList();
				checkStatus(0);
				restoreConfigs();
				updateGrid();
			}
		});

		Button clearStorage = new Button("Clear Storage");
		clearStorage.addClickHandler(new ClickHandler() {
			public void onClick(ClickEvent event) {
				resetStorage();
			}
		});
		saveConfig.addClickHandler(new ClickHandler() {
			public void onClick(ClickEvent event) {
				configNum++;
				saveConfig();
			}
		});


		final Button checkSat = new Button("Check satellite");
		checkSat.addClickHandler(new ClickHandler() {
			public void onClick(ClickEvent event) {
				int index = satNum.getSelectedIndex();
				int satellite = Integer.parseInt(satNum.getItemText(index));
				loadscripts(satellite);
				checkSat.setEnabled(false);
			}
		});		

		scrollAddForm.add(addform);
		addform.setWidget(0, 0, new Label("Module ID"));
		addform.setWidget(0, 1, idBox);
		addform.setWidget(1, 0, new Label("X Location"));
		addform.setWidget(1, 1, xBox);
		addform.setWidget(2, 0, new Label("Y Location"));
		addform.setWidget(2, 1, yBox);
		addform.setWidget(3, 0, new Label("Condition"));
		addform.setWidget(3, 1, condList);
		addform.setWidget(4, 0, new Label("Turns"));
		addform.setWidget(4, 1, orientList);
		addform.setWidget(5, 1, addMod);
		addform.setWidget(7, 0, satNum);
		addform.setWidget(7, 1, checkSat);
		addform.setWidget(8, 0, saveMod);
		addform.setWidget(8, 1, loadMod);
		addform.setWidget(9, 0, clearStorage);
		addform.setWidget(9, 1, loadStore);
		addform.setWidth("275px");
		addform.setHeight("0px");

		for(int i = 0; i < 10; i ++){
			ModContainer[i] = new ScrollPanel();
			Mods[i] = new FlexTable();
			ModContainer[i].add(Mods[i]);
		}

		panel.add(scrollAddForm, "Add New Module", 3);
		for(int i =0; i < modTypes.length ; i++){
			panel.add(ModContainer[i],modTypes[i] + " ("+Mods[i].getRowCount()+")", 3);
		}

		addMod.addClickHandler(new ClickHandler() {
			public void onClick(ClickEvent event) {
				addModuleToSystem(Integer.parseInt(xBox.getText()),
						Integer.parseInt(yBox.getText()),
						Integer.parseInt(idBox.getText()),
						condList.getItemText(condList.getSelectedIndex()),
						orientList.getItemText(orientList.getSelectedIndex()));
			}
		});		

		ScrollPanel sp = new ScrollPanel();		
		sp.add(g);

		// Create a three-pane layout with splitters. 
		SplitLayoutPanel splitPanel = new SplitLayoutPanel();
		splitPanel.addWest((panel), 275);
		splitPanel.addNorth((sp), 625);

		//Displays weather feed
		Image logo = new Image("images/logo.png");
		PushButton logoButton = new PushButton(logo);
		logoButton.addClickHandler(new ClickHandler() {
			public void onClick(ClickEvent event) {
				Weather feed = new Weather();
				feed.getResponse();
			}});
		splitPanel.addEast((logoButton), 125);

		//splitPanel.add(alertButton);
		// Attach the LayoutPanel to the RootLayoutPanel. The latter will listen for
		// resize events on the window to ensure that its children are informed of
		// possible size changes.
		RootLayoutPanel rp = RootLayoutPanel.get();
		rp.add(splitPanel);	

		bottomPanel.setWidget(0, 0, saveConfig);
		bottomPanel.setWidget(1, 0, setupBuildConfigurationPanel());
		scrollBottomPanel.add(bottomPanel);
		splitPanel.add(scrollBottomPanel);

		checkStatus(0);
		updateGrid();
	}

	/**
	 * Build the configurations panel. This panel contains buttons allowing
	 * the user to select and build specific base configurations.
	 * @param parentPanel The panel that this build configurations will be 
	 * added to.
	 */
	public Grid setupBuildConfigurationPanel() {

		// Setup button to build first minimum configuration
		minConfigBtn1 = new Button ("Minimum Config 1");
		minConfigBtn1.setEnabled(false);	// Not enabled until enough modules present
		minConfigBtn1.setHeight("50px");	// Match height of image buttons

		// Event code for button 1
		minConfigBtn1.addClickHandler(new ClickHandler() {
			public void onClick(ClickEvent event) {

				clearModuleIcons();
				// Array to store module locations
				Module[][] baseConfiguration = new Module[4][4];

				// Modules needed to construct minimum configuration
				Module plain1 = modList.removeByType(Module.typeavail[0]);
				Module plain2 = modList.removeByType(Module.typeavail[0]);
				Module plain3 = modList.removeByType(Module.typeavail[0]);
				Module dorm = modList.removeByType(Module.typeavail[1]);
				Module sanitation = modList.removeByType(Module.typeavail[2]);
				Module food = modList.removeByType(Module.typeavail[3]);
				Module canteen = modList.removeByType(Module.typeavail[5]);
				Module power = modList.removeByType(Module.typeavail[6]);
				Module control = modList.removeByType(Module.typeavail[7]);
				Module airlock = modList.removeByType(Module.typeavail[8]);

				// Build configuration using modules
				baseConfiguration[0][1] = sanitation;
				baseConfiguration[0][2] = control;
				baseConfiguration[1][0] = dorm;
				baseConfiguration[1][1] = plain1;
				baseConfiguration[1][2] = plain2;
				baseConfiguration[1][3] = airlock;
				baseConfiguration[2][0] = canteen;
				baseConfiguration[2][1] = plain3;
				baseConfiguration[2][2] = power;
				baseConfiguration[3][1] = food;

				// Add modules back to module list
				modList.add(plain1);
				modList.add(plain2);
				modList.add(plain3);
				modList.add(dorm);
				modList.add(sanitation);
				modList.add(food);
				modList.add(canteen);
				modList.add(power);
				modList.add(control);
				modList.add(airlock);

				placeBaseConfiguration(baseConfiguration);
			}
		});

		minConfigBtn2 = new Button ("Minimum Config 2");
		minConfigBtn2.setEnabled(false);
		minConfigBtn2.setHeight("50px");
		// Event code for button 2
		minConfigBtn2.addClickHandler(new ClickHandler() {
			public void onClick(ClickEvent event) {

				clearModuleIcons();

				// Array to store module locations
				Module[][] baseConfiguration = new Module[4][3];

				// Modules needed to construct minimum configuration
				Module plain1 = modList.removeByType(Module.typeavail[0]);
				Module plain2 = modList.removeByType(Module.typeavail[0]);
				Module plain3 = modList.removeByType(Module.typeavail[0]);
				Module dorm = modList.removeByType(Module.typeavail[1]);
				Module sanitation = modList.removeByType(Module.typeavail[2]);
				Module food = modList.removeByType(Module.typeavail[3]);
				Module canteen = modList.removeByType(Module.typeavail[5]);
				Module power = modList.removeByType(Module.typeavail[6]);
				Module control = modList.removeByType(Module.typeavail[7]);
				Module airlock = modList.removeByType(Module.typeavail[8]);

				// Build configuration using modules
				baseConfiguration[0][1] = airlock;
				baseConfiguration[1][0] = power;
				baseConfiguration[1][1] = plain1;
				baseConfiguration[1][2] = sanitation;
				baseConfiguration[2][0] = control;
				baseConfiguration[2][1] = plain2;
				baseConfiguration[2][2] = dorm;
				baseConfiguration[3][0] = food;
				baseConfiguration[3][1] = plain3;
				baseConfiguration[3][2] = canteen;

				// Add modules back to module list
				modList.add(plain1);
				modList.add(plain2);
				modList.add(plain3);
				modList.add(dorm);
				modList.add(sanitation);
				modList.add(food);
				modList.add(canteen);
				modList.add(power);
				modList.add(control);
				modList.add(airlock);

				placeBaseConfiguration(baseConfiguration);
			}
		});

		minConfigBtn3 = new Button ("Minimum Config 3");
		minConfigBtn3.setEnabled(false);
		minConfigBtn3.setHeight("50px");
		// Event code for button 3
		minConfigBtn3.addClickHandler(new ClickHandler() {
			public void onClick(ClickEvent event) {

				clearModuleIcons();
				// Array to store module locations
				Module[][] baseConfiguration = new Module[3][4];

				// Modules needed to construct minimum configuration
				Module plain1 = modList.removeByType(Module.typeavail[0]);
				Module plain2 = modList.removeByType(Module.typeavail[0]);
				Module plain3 = modList.removeByType(Module.typeavail[0]);
				Module dorm = modList.removeByType(Module.typeavail[1]);
				Module sanitation = modList.removeByType(Module.typeavail[2]);
				Module food = modList.removeByType(Module.typeavail[3]);
				Module canteen = modList.removeByType(Module.typeavail[5]);
				Module power = modList.removeByType(Module.typeavail[6]);
				Module control = modList.removeByType(Module.typeavail[7]);
				Module airlock = modList.removeByType(Module.typeavail[8]);

				// Build configuration using modules
				baseConfiguration[0][0] = sanitation;
				baseConfiguration[0][1] = dorm;
				baseConfiguration[0][2] = canteen;
				baseConfiguration[1][0] = plain1;
				baseConfiguration[1][1] = plain2;
				baseConfiguration[1][2] = plain3;
				baseConfiguration[1][3] = airlock;
				baseConfiguration[2][0] = control;
				baseConfiguration[2][1] = power;
				baseConfiguration[2][2] = food;

				// Add modules back to module list
				modList.add(plain1);
				modList.add(plain2);
				modList.add(plain3);
				modList.add(dorm);
				modList.add(sanitation);
				modList.add(food);
				modList.add(canteen);
				modList.add(power);
				modList.add(control);
				modList.add(airlock);

				placeBaseConfiguration(baseConfiguration);
			}
		});

		crossBaseBtn = new PushButton(new Image("images/CrossBase.png"));
		crossBaseBtn.setPixelSize(50, 50);
		crossBaseBtn.addClickHandler(new ClickHandler() {
			public void onClick(ClickEvent event) {

				clearModuleIcons();

				ModuleList m = new ModuleList();
				for(int i = 0; i < modList.count(); i ++){
					Module a = modList.getat(i);
					m.add(a);
				}

				CrossBase cBase = new CrossBase(m);
				Module[][] output = cBase.BuildBase();

				placeBaseConfiguration(output);
			}
		});

		HBaseBtn = new PushButton(new Image("images/HBase.png"));
		HBaseBtn.setPixelSize(50, 50);
		HBaseBtn.addClickHandler(new ClickHandler() {
			public void onClick(ClickEvent event) {

				clearModuleIcons();

				ModuleList m = new ModuleList();
				for(int i = 0; i < modList.count(); i ++){
					Module a = modList.getat(i);
					m.add(a);
				}
				HBase HBase = new HBase(m);
				Module[][] output = HBase.BuildBase();

				placeBaseConfiguration(output);
			}
		});

		sixWingBaseBtn = new PushButton(new Image("images/SixWing.png"));
		sixWingBaseBtn.setPixelSize(50, 50);
		sixWingBaseBtn.addClickHandler(new ClickHandler() {
			public void onClick(ClickEvent event) {

				clearModuleIcons();

				ModuleList m = new ModuleList();
				for(int i = 0; i < modList.count(); i ++){
					Module a = modList.getat(i);
					m.add(a);
				}
				SixWing sixWingBase = new SixWing(m);
				Module[][] output = sixWingBase.BuildBase();

				placeBaseConfiguration(output);
			}
		});

		Grid configPanel = new Grid(1, 6);
		configPanel.setWidget(0, 0, minConfigBtn1);
		configPanel.setWidget(0, 1, minConfigBtn2);
		configPanel.setWidget(0, 2, minConfigBtn3);
		configPanel.setWidget(0, 3, crossBaseBtn);
		configPanel.setWidget(0, 4, HBaseBtn);
		configPanel.setWidget(0, 5, sixWingBaseBtn);
		return configPanel;
	}

	public void addModuleToSystem(final int x, final int y, final int id, String cond, String orient){
		int panel_index = panelIndex(id);
		boolean check_for_previous_id = modList.add(x,y,id,cond, orient);
		boolean check_x_bounds = false;
		boolean check_y_bounds = false;
		if (g.getColumnCount() - x >=0){
			check_x_bounds = true;
		}
		if (g.getRowCount() - y >=0){
			check_y_bounds = true;
		}
		if((check_x_bounds == true) && (check_y_bounds == true) && (check_for_previous_id == true)){
			final ScrollPanel s = (ScrollPanel) panel.getWidget(panel_index);
			FlexTable t = (FlexTable) s.getWidget();
			int row = t.getRowCount();
			t.setWidget(row, 0, new Label (id + " at (" + x + "," + y + ")" +
					" Condition: " + cond + ", Orientation: " + orient));
			Button minus = new Button("-");
			minus.addClickHandler(new ClickHandler(){
				public void onClick(ClickEvent event) {
					modList.remove(id);
					int panel_reindex = panelIndex(id);
					FlexTable t = Mods[panel_reindex-1];
					for (int i = 0; i < t.getRowCount(); i ++){
						String text_Within_ft = t.getText(i, 0);
						int space_at = text_Within_ft.indexOf(' ');
						int id_num = Integer.parseInt(text_Within_ft.substring(0, space_at));
						if (id_num == id){
							t.removeRow(i);
							g.setWidget(((g.getRowCount()-y)),x-1,new Image("images/ground.png"));
							panel.remove(panel_reindex);
							int count = t.getRowCount();
							panel.insert(s, modTypes[panel_reindex-1] + " (" + count + ")", 3, panel_reindex);
							modList.incVal(ModuleList.DOWN,panel_reindex-1);
							if(minreached == true){
								minreached = modList.minAvail();
								if (minreached == false){
									minConfigBtn1.setEnabled(false);
									minConfigBtn2.setEnabled(false);
									minConfigBtn3.setEnabled(false);
									Window.alert("min config no longer present!");
								}
							}
						}
					}
				}
			});
			t.setWidget(row, 1, minus);
			panel.remove(panel_index);
			row = t.getRowCount();
			panel.insert(s, modTypes[panel_index-1] + " (" + row + ")", 3, panel_index);
			modList.incVal(ModuleList.UP,panel_index-1);
			g.setWidget((g.getRowCount() - y),x-1,new Image("images/"+modTypes[panel_index-1]+".png"));
			checkStatus(1);
		} else if (check_for_previous_id == true){
			Window.alert("Id or X Y combo has already been accounted for, module " + id + " failed to add");
			idBox.setText("");
		} else if (check_y_bounds == true){
			Window.alert("y: "+ y +" out of grid bounds, module " + id + " failed to add");
			yBox.setText("");
		} else if (check_x_bounds == true){
			Window.alert("x: "+ x +" out of grid bounds, module " + id + " failed to add");
			xBox.setText("");
		}
	}

	private void loadscripts(int searchForMe){
		String url = "http://www.d.umn.edu/~abrooks/TestCases.php?q="+searchForMe;
		url = URL.encode(url);


		// Send request to server and catch any errors.
		RequestBuilder builder = new RequestBuilder(RequestBuilder.GET, url);
		try {
			Request request = builder.sendRequest(null, new RequestCallback() {

				public void onError(Request request, Throwable exception) {
					Window.alert("onError: Couldn't retrieve JSON");
				}

				public void onResponseReceived(Request request, Response response) {
					if (200 == response.getStatusCode()) {
						String rt = response.getText();
						String sAll = rt;
						JSONArray jA = 
							(JSONArray)JSONParser.parseLenient(sAll);
						JSONNumber jN1,jN2,jN3,jN4;
						JSONString jS1;
						double id;
						double x;
						double y;
						String cond;
						double orient;
						for (int i = 0; i < jA.size(); i++) {
							JSONObject jO = (JSONObject)jA.get(i);
							jN1 = (JSONNumber) jO.get("code");
							id = jN1.doubleValue();
							jS1 = (JSONString) jO.get("status");
							cond = jS1.stringValue();
							jN4 = (JSONNumber) jO.get("turns");
							orient = jN4.doubleValue();
							jN2 = (JSONNumber) jO.get("X");
							x = jN2.doubleValue();
							jN3 = (JSONNumber) jO.get("Y");
							y = jN3.doubleValue();
							int intx = (int) x;
							int inty = (int) y;
							int intid = (int) id;
							String stringOrient = String.valueOf(orient);
							addModuleToSystem(intx,inty ,intid, cond, stringOrient);
						}
					} else {
						Window.alert("Couldn't retrieve JSON (" + response.getStatusText()
								+ ")");
					}
				}
			});
		} catch (RequestException e) {
			Window.alert("RequestException: Couldn't retrieve JSON");
		}
	}

	private boolean isSandyAreaOverlap(int xLocation, int yLocation, int configWidth, 
			int configHeight) {
		if ((xLocation >= sandyMinX && xLocation <= sandyMaxX
				|| (xLocation + configWidth) >= sandyMinX && (xLocation + configWidth) <= sandyMaxX)
				&& (yLocation >= sandyMinY && yLocation <= sandyMaxY
						|| (yLocation + configHeight) >= sandyMinY && (yLocation + configHeight) <= sandyMaxY)) {
			return true;
		} else {
			return false;
		}
	}

	/**
	 * Takes a completed base configuration and places it on the grid.
	 * @param configuration The 2D array holding the modules that make up
	 * 		a completed base configuration.
	 */
	private void placeBaseConfiguration(Module[][] configuration) {

		/*
		 * First find the center-of-gravity of all the modules in the
		 * configuration. This is found by finding the location that is
		 * central to all the invluded modules
		 */
		int xTotal = 0;
		int yTotal = 0;
		int moduleCount = 0;

		// Loop through modules, get sum of X and Y values
		for (int row = 0; row < configuration.length; row++) {
			for (int col = 0; col < configuration[0].length; col++) {
				if (configuration[row][col] != null) {
					// need to make sure we are getting locations from original module list.
					xTotal += modList.getByID(configuration[row][col].getId()).getCurrX();
					yTotal += modList.getByID(configuration[row][col].getId()).getCurrY();
					moduleCount++;
				}
			}
		}

		/*
		 * Find the central coordinate location. This is where we want
		 * the center of the base to be located at.
		 */
		int xAvg = xTotal / moduleCount;
		int yAvg = yTotal / moduleCount;

		/*
		 * Need to take into account the size of the base.
		 * We want the central location to be at the center at the base,
		 * not one of the corners of the base.
		 * Because the base will be added to the grid with respect to the 
		 * upper left corner (array location 0,0), find where that location is.
		 */
		int xCorner = xAvg - (configuration.length / 2);
		int yCorner = yAvg - (configuration[0].length / 2);

		// Make sure this is not off the bounds of the map in the x direction.
		if ((this.g.getColumnCount() - xCorner) < configuration[0].length) {
			xCorner = this.g.getColumnCount() - configuration[0].length;
		} else if (xCorner < 1) {
			xCorner = 1;
		}
		// Make sure this is not off the bounds of the map in the y direction.
		if ((this.g.getRowCount() - yCorner) < configuration.length) {
			yCorner = this.g.getRowCount() - configuration.length;
		} else if (yCorner < 1) {
			//yCorner = configuration.length;
			yCorner = 1;
		}

		// Take into account the sandy area
		while (isSandyAreaOverlap(xCorner + 1, yCorner, configuration.length, configuration[0].length)) {
			yCorner = yCorner - 1;
		}

		// We now have the correct location to build the base.
		// Loop through each element of 2D module configuration array
		for(int row = 0; row < configuration.length ; row++){
			for(int col = 0; col < configuration[0].length ; col++){
				// Check if this element is a module
				if (configuration[row][col] != null){

					// Move module into position on map
					Module temp = configuration[row][col];
					Module mod = modList.getByID(temp.getId());

					/*
					 * Need to take into account both the corner location
					 * (which is where in the map the base should be built) 
					 * and the array location (which is where in the 
					 * configuration a given module should be placed).
					 */
					int newX = xCorner + col + 1;
					int newY = yCorner + row;					
					mod.setCurrX(newX); 
					mod.setCurrY(newY);
				}
			}
		}
		updateModuleIcons();
	}

	/**
	 * Clears all module icons from the grid and replaces them with 
	 * the default ground image.
	 * This method needs to be called at the start of base configuration before
	 * any modules have their location modified.
	 */
	private void clearModuleIcons() {

		// Loop through modules, set their grid locations to display nothing
		int rowcount = g.getRowCount();
		for(int i = 0; i < modList.count(); i++){
			Module mod = modList.getat(i); 
			int x = mod.getCurrX();
			int y = mod.getCurrY();
			g.setWidget((rowcount)-y,(x-1), new Image(groundLocation));
		}
	}

	/**
	 * Update the module icons by placing a module icon at each respective
	 * location on the grid for every module in the module list.
	 * This method needs to be called at the end of base configuration after 
	 * all updating of module location is complete.
	 */
	private void updateModuleIcons() {
		// Loop through modules, set their grid locations to display modules
		int rowcount = g.getRowCount();
		for(int i = 0; i < modList.count(); i++){
			Module mod = modList.getat(i); 
			int x = mod.getCurrX();
			int y = mod.getCurrY();
			int id = mod.getId();
			int panel_index = panelIndex(id)-1;
			g.setWidget(rowcount-y,(x-1), new Image("images/"+modTypes[panel_index]+".png"));
		}
	}

	private void updateGrid(){
		g.clear();
		int rowcount = g.getRowCount();
		for(int row = 0; row < rowcount; row++){
			for(int col = 0; col < g.getColumnCount(); col++){
				g.setWidget(row,col,new Image(groundLocation));
			}
		}
		for(int col = 40; col < 50; col++){
			for(int row = 0; row < 10; row++ ){
				g.setWidget(row, col, new Image("images/red.png"));
			}
		}
		for(int i = 0; i < modList.count(); i++){
			Module mod = modList.getat(i);
			int id = mod.getId();
			int x = mod.getCurrX();
			int y = mod.getCurrY();
			int panel_index = panelIndex(id)-1;

			// y-value = rowcount - 1 because rows are 0-indexed (row 50 = row 49 in grid)
			// 	then subtract y because row 1 is row 49 on the grid.
			// x-value = x - 1 because columns are zero indexed
			g.setWidget((rowcount)-y,(x-1), new Image("images/"+modTypes[panel_index]+".png"));
		}
	}

	private void updateAccordion(final int x, final int y, final int id, String cond, String orient){
		int panel_index = panelIndex(id);
		final ScrollPanel s = (ScrollPanel) panel.getWidget(panel_index);
		FlexTable t = (FlexTable) s.getWidget();
		int row = t.getRowCount();
		t.setWidget(row, 0, new Label (id + " at (" + x + "," + y + ")" +
				" Condition: " + cond + ", Turns: " + orient));
		Button minus = new Button("-");
		minus.addClickHandler(new ClickHandler(){
			public void onClick(ClickEvent event) {
				modList.remove(id);
				int panel_reindex = panelIndex(id);
				FlexTable t = Mods[panel_reindex-1];
				for (int i = 0; i < t.getRowCount(); i ++){
					String text_Within_ft = t.getText(i, 0);
					int space_at = text_Within_ft.indexOf(' ');
					int id_num = Integer.parseInt(text_Within_ft.substring(0, space_at));
					if (id_num == id){
						t.removeRow(i);
						g.setWidget((g.getRowCount() - y),x-1,new Image("images/ground.png"));
						panel.remove(panel_reindex);
						int count = t.getRowCount();
						panel.insert(s, modTypes[panel_reindex-1] + " (" + count + ")", 3, panel_reindex);
						modList.incVal(ModuleList.DOWN,panel_reindex-1);
						checkStatus(-1);
					}
				}
			}
		});
		t.setWidget(row, 1, minus);
		panel.remove(panel_index);
		row = t.getRowCount();
		panel.insert(s, modTypes[panel_index-1] + " (" + row + ")", 3, panel_index);
		modList.incVal(ModuleList.UP,panel_index-1);

	}
	private int panelIndex(int id){
		int panel_index = -1;
		String id2 = Module.id_to_type(id);
		for(int i = 0; i < modTypes.length ; i ++){
			if(modTypes[i] == id2){
				panel_index = i+1;
				break;
			}
		}
		return panel_index;
	}

	private void storeList(){
		moduleStore = Storage.getLocalStorageIfSupported();
		if (moduleStore != null) {
			moduleStore.setItem(modListKey, modList.storageengine());
		}
	}

	private void restoreList(){
		moduleStore = Storage.getLocalStorageIfSupported();
		if (moduleStore != null) {
			String text = moduleStore.getItem(modListKey);
			if (text != null){
				modList.reverseStorage(text);
				updateGrid();
				for(int i = 0; i < modList.count(); i++){
					Module m = modList.getat(i);
					updateAccordion(m.getCurrX(),m.getCurrY(),m.getId(),m.getCondition(),m.getOrientation());
				}
			}
		}
	}

	private void restoreConfigs(){
		moduleStore = Storage.getLocalStorageIfSupported();
		if (moduleStore != null) {
			String mC= moduleStore.getItem(configWatch);
			if(mC != null){
				configNum = Integer.parseInt(mC);
				for (int i = 1; i <= configNum ; i ++){
					String mCat = moduleStore.getItem(configKey+i);
					if(mCat != null){
						addShowButton(i);
					}

				}
			}
		}
	}

	private void saveConfig(){
		moduleStore = Storage.getLocalStorageIfSupported();
		if (moduleStore != null) {
			moduleStore.setItem(configKey+configNum, modList.storageConfig());
			moduleStore.setItem(configWatch,String.valueOf(configNum));
			addShowButton(configNum);
		}

	}

	private void addShowButton(final int buttonNum){		
		Button show = new Button(configKey+buttonNum);
		show.addClickHandler(new ClickHandler(){
			public void onClick(ClickEvent event) {
				moduleStore = Storage.getLocalStorageIfSupported();
				if (moduleStore != null) {
					String text = moduleStore.getItem(configKey+buttonNum);
					if (text != null){
						modList.reverseStorageConfig(text);
						updateGrid();
					}
				}
			}
		});
		int i = 0;
		while (bottomPanel.isCellPresent(0, i) == true){
			i++;
		}
		bottomPanel.setWidget(0, i, show);

	}

	private void resetStorage(){
		moduleStore = Storage.getLocalStorageIfSupported();
		if (moduleStore != null){
			moduleStore.clear();
		}
	}

	// var is 1, 0, or -1
	// if var is -1, than a minus test should be performed (only on mod remove)
	// if var is 1, than an addition test should be performed (only on mod add)
	// if var is 0, than neither test should be performed ( only on localstorage read)
	private void checkStatus(int var){

		if ((minreached == true) && (var == -1)){
			minreached = modList.minAvail();
			if (minreached == false){
				disableBuildButtons();
				saveConfig.setEnabled(false);
				Window.alert("min config no longer present!");
			}
		} else if ((minreached == true) && ( var == 0)){
			disableBuildButtons();
			saveConfig.setEnabled(false);
		} else if ((minreached == false) && (var == 1)){
			minreached = modList.minAvail();
			if (minreached == true){
				enableBuildButtons();
				saveConfig.setEnabled(true);
				Window.alert("min config present!");
			}
		} else if ((minreached == false) && (var == 0)){
			minreached = modList.minAvail();
			if (minreached == true){
				enableBuildButtons();
				saveConfig.setEnabled(true);
			} else {
				disableBuildButtons();
				saveConfig.setEnabled(false);	
			}

		}
	}

	private void enableBuildButtons() {
		minConfigBtn1.setEnabled(true);
		minConfigBtn2.setEnabled(true);
		minConfigBtn3.setEnabled(true);
		crossBaseBtn.setEnabled(true);
		HBaseBtn.setEnabled(true);
		sixWingBaseBtn.setEnabled(true);
	}

	private void disableBuildButtons() {
		minConfigBtn1.setEnabled(false);
		minConfigBtn2.setEnabled(false);
		minConfigBtn3.setEnabled(false);
		crossBaseBtn.setEnabled(false);
		HBaseBtn.setEnabled(false);
		sixWingBaseBtn.setEnabled(false);
	}
}
